Scrawl.php

<?php

namespace Tlf;


class Scrawl {

    use Scrawl\Commands;

    protected $extensions;
    protected $configs;
    public $dir;
    protected $outputs = [];


    public function error($header, $message){
        echo "\033[0;31m$header:\033[0m $message\033[0;31m...\033[0m\n";
    }

    /**
     *
     * @param $project_dir root dir of the project
     * @param $configs array of configurations
     */
    public function __construct(string $project_dir, array $configs=[]){
        $this->dir = $project_dir;

        //arrayify configs
        $copy = $configs;
        foreach ($copy as $key=>$opt){
            if (!is_array($opt)){
                $configs[$key] = [$opt];
            }
        }
        
        //perform autoload (even though this should just be done through composer)
        foreach ($configs['autoload']['classmap']??[] as $dir){
            \Tlf\Scrawl\Utility::autoload($project_dir.'/'.$dir);
        }

        $this->configs = $configs;

    
    }

    public function add_standard_extensions(){
        $this->addExtension(new Scrawl\Ext\DefaultExt\CopyReadme($this));
        $this->addExtension(new Scrawl\Ext\DefaultExt\ExportDocBlock($this));
        $this->addExtension(new Scrawl\Ext\DefaultExt\ExportStartEnd($this));
        $this->addExtension(new Scrawl\Ext\DefaultExt\WriteExportList($this));
        $this->addExtension(new Scrawl\Ext\DefaultExt\MarkdownVerbs($this));

        $this->addExtension(new Scrawl\Ext\MdVerb\SimpleVerbs($this));
        $this->addExtension(new Scrawl\Ext\MdVerb\Ast($this));


        $this->addExtension(new Scrawl\Ext\Lang\Php($this));
        // $this->addExtension(new Scrawl\Ext\Lang\Bash($this));
    }


    public function pathToRootFrom($configuredDirectory){
        $relPath = $this->getConfig('dir.'.$configuredDirectory);
        if ($relPath===null) return null;
        $relPath = $relPath[0];
        $relPath = str_replace('\\','/',$relPath);
        $parts = explode('/', $relPath);
        $retRelPath = '';
        foreach ($parts as $p){
            $retRelPath .= '../';
        }
        return $retRelPath;
    }

    public function getConfig($key){
        return $this->configs[$key] ?? null;
    }

    /**
     * Get an array of groups this extensions is in
     */
    public function get_extension_groups(object $extension): array{

        $groups = [];
        $interfaces = class_implements($extension);
        $lookFor = 'Tlf\\Scrawl\\ExtensionType';
        foreach ($interfaces as $i){
            if (substr($i, 0, strlen($lookFor)) !== $lookFor){
                continue;
            }
            $group = 
                strtolower( 
                    substr(
                        $i, 
                        strlen($lookFor)+1,
                        -strlen('Interface')
                    ) 
                );
            $groups[] = $group;
        }
        return $groups;
    }

    public function addExtension(object $extension){
        $groups = $this->get_extension_groups($extension);
        foreach ($groups as $g){
            $this->extensions[$g][] = $extension;
        }
    }

    public function getExtensions($group){
        return $this->extensions[$group];
    }

    public function addOutput(string $group, string $key, $content){
        $existing = $this->output[$group][$key] ?? null;
        if ($existing!==null)throw new \Exception("Output for '{$group}', '{$key}' has already been set...");
        $this->outputs[$group][$key] = $content;
    }

    public function setOutput(string $group, string $key, $content){
        $this->outputs[$group][$key] = $content;
    }

    public function getOutput(string $group, string $key) {
        return $this->outputs[$group][$key] ?? null;
    }

    public function getOutputs(?string $group=null): ?array{
        if ($group===null)return $this->outputs;
        return $this->outputs[$group] ?? null;
    }

    public function extCall(string $group, ?string $methodName, ...$args){
        $rets = [];
        foreach ($this->getExtensions($group) as $ext){
            if (is_object($ext)){
                $rets[] = $ext->$methodName(...$args);
            } else if (is_callable($ext)){
                $rets[] = $ext(...$args);
            }
        }
        return $rets;
    }

    public function getFilesToDocument(){
        $root = $this->dir;

        $codeDirs = $this->configs['dir.code'];

        $codeExts = $this->configs['file.code.ext'];

        $files = [];
        foreach ($codeDirs as $d){
            $newFiles = Scrawl\Utility::allFilesFromDir($root, $d, $codeExts);
            $files = [...$files, ...$newFiles];
        }

        return $files;
    }

    public function getTemplateFiles(){
        $root = $this->dir;
        $templateDirs = $this->configs['dir.template'];
        $templateExts = $this->configs['file.template.ext'];
        
        $files = [];
        foreach ($templateDirs as $td){
            $newFiles = Scrawl\Utility::allFilesFromDir($root.'/'.$td, '', $templateExts);
            $files = [...$files, ...$newFiles];
        }

        return $files;
    }

    public function writeFile(Scrawl\File $outputFile, $dryRun=false){
        
        $relPath = $outputFile->relPath;
        $nb = strlen($outputFile->content());
        echo "Write $nb chars to $relPath\n";

        if ($dryRun){
            return;
        }
        
        $outputFile->write();
    }
    
    public function loadTemplate($ext, $templateName, array $argList){
        $template = __DIR__.'/Template/'.$templateName.'.php';
        if (!is_file($template))$template = __DIR__.'/Template/'.$templateName.'.md.php';
        if (!is_file($template))$template = $this->dir.'/'.$this->configs['dir.template_files'][0].'/'.$templateName.'.md.php';
        if (!is_file($template))$template = $this->dir.'/'.$this->configs['dir.template_files'][0].'/'.$templateName.'.php';
        if (!is_file($template)){
            echo "\nError: Template '$templateName' not found.\n";
            return "Template '$templateName' not found.";
        }
        $argv = array_values($argList);
        $scrawl = $this;
        array_unshift($argv, $_SERVER['argv'][0]??null);
        ob_start();
        require($template);
        $final = ob_get_clean();
        return trim($final);
    }
}